"""
ConnLLM V2 提供商基类
提供基础提供商实现
"""

from typing import Dict, Any, List, Optional, Generator, Union, Tuple
import logging
import time
import json
from abc import abstractmethod

from .interfaces import IProvider
from .config import ConfigManagerV2
from .capability import CapabilityManagerV2, ModelCapabilityManagerV2
from .http import HTTPClientV2

logger = logging.getLogger("connllm.core_v2.provider")

class BaseProviderV2(IProvider):
	"""基础提供商实现"""
	
	def __init__(self, config: Dict[str, Any]):
		"""
		初始化提供商
		
		Args:
			config: 配置字典
		"""
		# 基础组件初始化
		self.config_manager = self._create_config_manager(config)
		self.http_client = self._setup_http_client()
		self.retry_handler = self._create_retry_handler()
		self.token_counter = self._create_token_counter()
		self.cost_calculator = self._create_cost_calculator()
		
		# 能力管理器初始化
		self.capability_manager = self._create_capability_manager()
		self.model_capability_manager = self._create_model_capability_manager()
		
		# 初始化能力
		self._init_capabilities()
		self._init_model_capabilities()
		
		# 处理器管道初始化
		self.request_processors = []
		self.response_processors = []
		self._build_processor_pipeline()
		
		logger.debug(f"已初始化{self.__class__.__name__}，模型: {self.config_manager.get_model()}")
	
	def complete(self, messages: List[Dict[str, Any]], stream: bool = False) -> Union[Dict[str, Any], Generator[str, None, None]]:
		"""
		执行LLM完成请求
		
		Args:
			messages: 消息列表
			stream: 是否使用流式输出
			
		Returns:
			非流式模式返回完整响应，流式模式返回文本生成器
		"""
		if stream:
			return self.complete_stream(messages)
		
		try:
			return self._complete_internal(messages)
		except Exception as e:
			logger.error(f"完成请求失败: {str(e)}")
			raise e
	
	def complete_stream(self, messages: List[Dict[str, Any]]) -> Generator[str, None, None]:
		"""
		执行LLM流式完成请求
		
		Args:
			messages: 消息列表
			
		Returns:
			文本生成器
		"""
		model = self.config_manager.get_model()
		
		# 检查流式输出能力
		if not self.model_capability_manager.model_supports("streaming", model):
			# 如果不支持流式输出，则使用非流式模式并一次性返回
			response = self._complete_internal(messages)
			text = self._extract_text_from_response(response)
			yield text
			return
		
		# 使用流式输出能力
		streaming = self.model_capability_manager.get("streaming")
		yield from streaming.stream_response(messages)
	
	def _complete_internal(self, messages: List[Dict[str, Any]], context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
		"""
		内部完成方法实现
		
		Args:
			messages: 消息列表
			context: 请求上下文（可选）
			
		Returns:
			API响应
		"""
		start_time = time.time()
		
		# 初始化上下文
		context = context or {}
		if "original_messages" not in context:
			context["original_messages"] = messages
		
		try:
			# 准备基本请求参数
			params = self._prepare_request_params(messages)
			
			# 应用所有请求处理器
			for processor in self.request_processors:
				params = processor.process_request(params, context)
			
			# 发送HTTP请求
			endpoint = self._get_completion_endpoint()
			response = self.http_client.request(
				method="POST",
				endpoint=endpoint,
				data=params
			)
			result = response.json()
			
			# 应用所有响应处理器
			for processor in self.response_processors:
				result = processor.process_response(result, context)
			
			# 检查是否需要重试请求（如工具调用）
			for processor in self.response_processors:
				if processor.should_retry_request(result, context):
					# 准备新消息
					new_messages = self._prepare_retry_messages(messages, result, context)
					context["retry_count"] = context.get("retry_count", 0) + 1
					
					if context.get("retry_count", 0) > 5:
						logger.warning(f"达到最大重试次数: {context['retry_count']}")
						break
						
					# 递归调用
					logger.debug(f"重试请求，重试次数: {context['retry_count']}")
					return self._complete_internal(new_messages, context)
			
			# 计算token使用量
			input_tokens, output_tokens = self._extract_token_usage(result)
			cost = self._calculate_cost(input_tokens, output_tokens)
			
			elapsed = time.time() - start_time
			logger.info(f"{self.__class__.__name__}请求完成，耗时: {elapsed:.2f}秒，"
					   f"模型: {self.config_manager.get_model()}, "
					   f"输入: {input_tokens}tokens, 输出: {output_tokens}tokens, "
					   f"成本: ${cost:.6f}")
			
			return result
			
		except Exception as e:
			elapsed = time.time() - start_time
			logger.error(f"{self.__class__.__name__}请求失败，耗时: {elapsed:.2f}秒，错误: {str(e)}")
			raise e
	
	def _build_processor_pipeline(self) -> None:
		"""
		构建处理器管道
		基于配置和能力动态配置处理器
		"""
		model = self.config_manager.get_model()
		
		# 从配置获取处理器配置
		pipeline_config = self.config_manager.get("processor_pipeline", [])
		
		# 如果没有配置，使用默认处理器构建
		if not pipeline_config:
			self._build_default_processor_pipeline(model)
			return
		
		# 按优先级排序
		pipeline_config.sort(key=lambda x: x.get("priority", 100))
		
		# 创建处理器
		for proc_config in pipeline_config:
			if not proc_config.get("enabled", True):
				continue
				
			processor = self._create_processor(proc_config["type"])
			if processor:
				# 根据处理器类型添加到相应列表
				if hasattr(processor, "process_request"):
					self.request_processors.append(processor)
				if hasattr(processor, "process_response"):
					self.response_processors.append(processor)
	
	def _build_default_processor_pipeline(self, model: str) -> None:
		"""
		构建默认处理器管道
		
		Args:
			model: 模型名称
		"""
		# 子类实现
		pass
	
	def _prepare_request_params(self, messages: List[Dict[str, Any]]) -> Dict[str, Any]:
		"""
		准备API请求参数
		
		Args:
			messages: 消息列表
			
		Returns:
			请求参数字典
		"""
		# 子类实现
		return {}
	
	def _prepare_retry_messages(self, messages: List[Dict[str, Any]], 
							   response: Dict[str, Any], 
							   context: Dict[str, Any]) -> List[Dict[str, Any]]:
		"""
		准备重试请求的消息列表
		
		Args:
			messages: 原始消息列表
			response: API响应
			context: 请求上下文
			
		Returns:
			新的消息列表
		"""
		# 基本实现，子类可重写
		new_messages = messages.copy()
		
		# 添加助手消息
		content = self._extract_text_from_response(response)
		assistant_message = {
			"role": "assistant",
			"content": content
		}
		
		# 添加工具调用信息（如果有）
		if "tool_calls" in context:
			assistant_message["tool_calls"] = context["tool_calls"]
		
		new_messages.append(assistant_message)
		
		# 添加工具结果（如果有）
		if "tool_results" in context:
			new_messages.extend(context["tool_results"])
		
		# 添加搜索结果（如果有）
		if "search_results" in context:
			search_results = context["search_results"]
			if isinstance(search_results, list):
				new_messages.extend(search_results)
			context["retry_with_search"] = True
		
		return new_messages
	
	def _extract_text_from_response(self, response: Dict[str, Any]) -> str:
		"""
		从响应中提取文本内容
		
		Args:
			response: API响应
			
		Returns:
			提取的文本内容
		"""
		# 基本实现，子类可重写
		try:
			if "choices" in response and len(response["choices"]) > 0:
				choice = response["choices"][0]
				
				# 检查message格式
				if "message" in choice and "content" in choice["message"]:
					return choice["message"]["content"] or ""
					
				# 检查delta格式（流式响应）
				if "delta" in choice and "content" in choice["delta"]:
					return choice["delta"]["content"] or ""
		except Exception as e:
			logger.error(f"从响应中提取文本失败: {str(e)}")
			
		return ""
	
	def _extract_token_usage(self, response: Dict[str, Any]) -> Tuple[int, int]:
		"""
		从响应中提取token使用量
		
		Args:
			response: API响应
			
		Returns:
			输入token数和输出token数
		"""
		try:
			if "usage" in response:
				usage = response["usage"]
				input_tokens = usage.get("prompt_tokens", 0)
				output_tokens = usage.get("completion_tokens", 0)
				return input_tokens, output_tokens
		except Exception as e:
			logger.warning(f"从响应中提取token使用量失败: {str(e)}")
			
		return 0, 0
	
	def _calculate_cost(self, input_tokens: int, output_tokens: int) -> float:
		"""
		计算成本
		
		Args:
			input_tokens: 输入token数
			output_tokens: 输出token数
			
		Returns:
			成本（美元）
		"""
		# 可以根据token用量计算成本，子类可重写
		return 0.0
	
	def _get_completion_endpoint(self) -> str:
		"""
		获取完成请求的API端点
		
		Returns:
			API端点路径
		"""
		# 子类实现
		return "/v1/chat/completions"
	
	def _get_default_headers(self) -> Dict[str, str]:
		"""
		获取默认HTTP头
		
		Returns:
			HTTP头字典
		"""
		# 基本实现，子类可重写
		api_key = self.config_manager.get("api_key", "")
		return {
			"Authorization": f"Bearer {api_key}",
			"Content-Type": "application/json"
		}
	
	def _setup_http_client(self) -> HTTPClientV2:
		"""
		设置HTTP客户端
		
		Returns:
			HTTP客户端实例
		"""
		# 获取API设置
		api_settings = self.config_manager.get_api_settings()
		
		base_url = api_settings.get("base_url", "")
		headers = self._get_default_headers()
		timeout = api_settings.get("timeout", 60)
		proxy = api_settings.get("proxy", None)
		
		return HTTPClientV2(
			base_url=base_url,
			default_headers=headers,
			timeout=timeout,
			proxy=proxy
		)
	
	def _create_config_manager(self, config: Dict[str, Any]) -> ConfigManagerV2:
		"""
		创建配置管理器
		
		Args:
			config: 配置字典
			
		Returns:
			配置管理器实例
		"""
		return ConfigManagerV2(config)
	
	def _create_capability_manager(self) -> CapabilityManagerV2:
		"""
		创建能力管理器
		
		Returns:
			能力管理器实例
		"""
		return CapabilityManagerV2(self)
	
	def _create_model_capability_manager(self) -> ModelCapabilityManagerV2:
		"""
		创建模型能力管理器
		
		Returns:
			模型能力管理器实例
		"""
		return ModelCapabilityManagerV2(self)
	
	def _create_retry_handler(self) -> Any:
		"""
		创建重试处理器
		
		Returns:
			重试处理器实例
		"""
		# 子类可实现
		return None
	
	def _create_token_counter(self) -> Any:
		"""
		创建Token计数器
		
		Returns:
			Token计数器实例
		"""
		# 子类可实现
		return None
	
	def _create_cost_calculator(self) -> Any:
		"""
		创建成本计算器
		
		Returns:
			成本计算器实例
		"""
		# 子类可实现
		return None
	
	def _create_processor(self, processor_type: str) -> Optional[Any]:
		"""
		创建指定类型的处理器
		
		Args:
			processor_type: 处理器类型名称
			
		Returns:
			处理器实例或None
		"""
		# 根据类型创建处理器，子类可重写
		from .processors.tool_call import ToolCallProcessor
		from .processors.web_search import WebSearchProcessor
		from .processors.thinking import ThinkingProcessor
		
		processor_map = {
			"tool_call": lambda: ToolCallProcessor(self.model_capability_manager.get("tool_calls")),
			"web_search": lambda: WebSearchProcessor(self.capability_manager.get("web_search")),
			"thinking": lambda: ThinkingProcessor(self.model_capability_manager.get("thinking"))
		}
		
		creator = processor_map.get(processor_type)
		if creator:
			try:
				return creator()
			except Exception as e:
				logger.error(f"创建处理器失败: {processor_type}, 错误: {str(e)}")
				
		return None
	
	@abstractmethod
	def _init_capabilities(self) -> None:
		"""初始化提供商级能力"""
		pass
	
	@abstractmethod
	def _init_model_capabilities(self) -> None:
		"""初始化模型级能力"""
		pass
